﻿#region License
/* **********************************************************************************
 * Copyright (c) Haugen Applications LLC
 * This source code is subject to terms and conditions of the MIT License
 * for UserScript. A copy of the license can be found on the License tab for this CodePlex release
 * By using this source code in any fashion, you are agreeing to be bound by the terms of the 
 * MIT License.
 * You must not remove this notice from this software.
 * **********************************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace UserScript.ExpressionParsing
{
    public static class ExpressionFunctionExecutor
    {
        internal static object ExecuteFunction(string FunctionName, object[] Arguments)
        {
            Type type = typeof (ExpressionFunctionExecutor);

            var methodOps = type.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance).Where(c => c.Name.TrimStart('@').Equals(FunctionName, StringComparison.CurrentCultureIgnoreCase));

            foreach(var method in methodOps)
            {
                var argEnumerator = Arguments.GetEnumerator();
                bool isMatch = true;

                List<object> argsWithDefaults = new List<object>();
                
                foreach(var parameter in method.GetParameters())
                {
                    if (argEnumerator.MoveNext())
                    {
                        if (argEnumerator.Current == null || parameter.ParameterType.IsAssignableFrom(argEnumerator.Current.GetType()))
                        {
                            argsWithDefaults.Add(argEnumerator.Current);
                        }
                        else
                        {
                            isMatch = false;
                            break;
                        }
                    }
                    else if(parameter.DefaultValue != null)
                    {
                        argsWithDefaults.Add(parameter.DefaultValue);
                    }
                    else
                    {
                        isMatch = false;
                        break;
                    }
                }

                if(isMatch)
                {
                    return method.Invoke(null, argsWithDefaults.ToArray());
                }
            }

            throw new FunctionNotFoundException() { FunctionName = FunctionName, Arguments = Arguments };
        }

        public static object @if(bool op, object t, object f)
        {
            return op ? t : f;
        }
        public static object @if(bool op, object t)
        {
            return op ? t : null;
        }

        public static int len(string arg)
        {
            return arg.Length;
        }

        public static bool isBlank(string arg)
        {
            return string.IsNullOrWhiteSpace(arg);
        }

        public static string format(object arg, string format)
        {
            return ExpressionFunctionExecutor.format(arg, format, null);
        }

        public static string format(object arg, string format, string culture)
        {
            if (arg == null)
                return null;

            IFormatProvider provider = null;

            if (culture != null)
            {
                provider = new CultureInfo(culture);
            }

            if (provider != null)
            {
                var cf = (ICustomFormatter) provider.GetFormat(typeof (ICustomFormatter));

                if (cf != null)
                {
                    var s = cf.Format(format, arg, provider);
                    if (s != null)
                        return s;
                }
            }

            var formattableArg = arg as IFormattable;

            if (formattableArg != null)
            {
                return formattableArg.ToString(format, provider);
            }
            
            return arg.ToString();
        }

        public static string padleft(string arg, int totalWidth)
        {
            return arg.PadLeft(totalWidth);
        }

        public static string padRight(string arg, int totalWidth)
        {
            return arg.PadRight(totalWidth);
        }

        public static double pow(double x, double y)
        {
            return Math.Pow(x, y);
        }
        public static double pow(int x, int y)
        {
            return Math.Pow(x, y);
        }
    }
}
